package com.hue.gulimail.gulimailsearch.thread;

import java.util.concurrent.*;

/**
 * 测试多线程
 * 开启多线程的方式：
 * 1.继承Thread类
 * 2.实现Runnable接口
 * 3.实现Callable接口+FutureTask（可以拿到返回结果，可以处理异常）
 * 4.使用线程池
 *
 * @author 姚凤桥
 */
public class TestThread {
    public static void main(String[] args) throws Exception {
//        testCompletableFuture();

//        testThreadLine();

//        testManyTask();

//        testManyTask2();

        testManyTask3();
    }

    /**
     * 测试FutureTask
     *
     * @throws Exception
     */
    public static void testFutureTask() throws Exception {
        System.out.println("main start...");

        //FutureTask
        FutureTask<Integer> futureTask = new FutureTask<>(() -> {
            return 10;
        });
        Thread thread = new Thread(futureTask);
        thread.start();

        System.out.println("main end..." + "res=" + futureTask.get());
    }

    /**
     * 测试线程池
     */
    public static ThreadPoolExecutor testExecutorsService() {
        /**
         * int corePoolSize:核心线程数，如果不设置allowCoreThreadTimeOut,那么一直存在
         * int maximumPoolSize:最大线程数
         * long keepAliveTime：当线程数量大于核心线程数时，会释放空闲时间超过keepAliveTime的线程
         * TimeUnit unit：时间单位
         * BlockingQueue<Runnable> workQueue：阻塞队列，当任务数量超过核心线程数时会将多余的任务放在阻塞队列中
         * ThreadFactory threadFactory：线程的创建工厂
         * RejectedExecutionHandler handler:拒绝策略，阻塞队列满了之后将按照这个策略来拒绝执行任务
         */
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                5,
                10,
                1000,
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(1000),
                Executors.defaultThreadFactory(),
                //丢弃当前任务
                new ThreadPoolExecutor.AbortPolicy());

        return threadPoolExecutor;
    }

    /**
     * 测试异步编排
     */
    public static void testCompletableFuture() throws ExecutionException, InterruptedException {
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                5,
                10,
                1000,
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(1000),
                Executors.defaultThreadFactory(),
                //丢弃当前任务
                new ThreadPoolExecutor.AbortPolicy());

        System.out.println("main start...");

        //使用指定的线程池来运行异步任务
//        CompletableFuture<Void> runAsync = CompletableFuture.runAsync(() -> {
//            System.out.println("哈哈哈");
//        }, threadPoolExecutor);

        CompletableFuture<Integer> supplyAsync = CompletableFuture.supplyAsync(() -> {
            return 1;
        }, threadPoolExecutor);

        //异步任务完成后需要执行的回调函数
        supplyAsync.whenComplete((res, throwable) -> {
            System.out.println("异步任务执行完成:res=" + res + ",exception=" + throwable);
        });

        //异步任务执行异常需要执行的回调函数
        supplyAsync.exceptionally((throwable -> -1));

        //异步任务执行完成后执行的回调函数
        supplyAsync.handle((res, throwable) -> res != null ? res : -1);

        Integer integer = supplyAsync.get();

        System.out.println("main end..." + "res = " + integer);
    }

    /**
     * 测试线程串行化
     */
    public static void testThreadLine() throws ExecutionException, InterruptedException {
        ThreadPoolExecutor threadPoolExecutor = testExecutorsService();

        //thenRunAsync不能接受上一步任务的返回结果
//        CompletableFuture.supplyAsync(() -> 1, threadPoolExecutor).thenRunAsync(() -> System.out.println("=========="));

        //thenAcceptAsync能接受上一步任务的返回结果，没有返回值
//        CompletableFuture.supplyAsync(() -> 1, threadPoolExecutor).thenAcceptAsync((res) -> System.out.println("res=" + res));

        //thenApplyAsync能接受上一步的返回结果，也有返回值供下一个任务调用
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> 1, threadPoolExecutor).thenApplyAsync((res) -> res * 2);
        System.out.println("res=" + future.get());
    }

    /**
     * 测试多任务组合(需要多个任务全部完成才能执行指定任务)
     */
    public static void testManyTask() throws ExecutionException, InterruptedException {
        ThreadPoolExecutor executor = testExecutorsService();

        //组合两个任务
        CompletableFuture<Void> future1 = CompletableFuture.runAsync(() -> System.out.println("task1执行完成"), executor);
        CompletableFuture<Void> future2 = CompletableFuture.runAsync(() -> System.out.println("task2执行完成"), executor);
        //runAfterBothAsync不需要前两个任务的返回值
//        future1.runAfterBothAsync(future2, () -> System.out.println("task3执行完成"), executor);

        //thenAcceptBothAsync需要前两个任务的返回值,但是没有返回值
//        future1.thenAcceptBothAsync(future2, (res1, res2) -> System.out.println("task3执行完成,res1=" + res1 + ",res2=" + res2), executor);

        //thenCombineAsync需要前两个任务的返回值，并且也有返回值供下一个任务使用
        CompletableFuture<String> future3 = future1.thenCombineAsync(future2, (res1, res2) -> res1 + "," + res2, executor);
        System.out.println(future3.get());

    }

    /**
     * 测试多任务组合(只要有一个任务完成就可以执行指定任务)
     */
    public static void testManyTask2() {
        ThreadPoolExecutor executor = testExecutorsService();

        CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> 1, executor);
        CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(() -> 2, executor);

        //runAfterEitherAsync不需要前面任务的返回值
//        future1.runAfterEitherAsync(future2, () -> System.out.println("任务3开始执行"), executor);

        //acceptEitherAsync需要前面任务的返回值(两个任务的返回值类型必须相同),但是没有返回值
//        future1.acceptEitherAsync(future2, (res) -> System.out.println("res=" + res), executor);

        //applyToEitherAsync需要前面任务的返回值，也有返回值供下个任务使用
        future1.applyToEitherAsync(future2, (res) -> res * 2, executor).thenAcceptAsync((res) -> System.out.println("res=" + res));
    }

    /**
     * 测试多任务组合
     */
    public static void testManyTask3() throws ExecutionException, InterruptedException {
        CompletableFuture<String> imgFuture = CompletableFuture.supplyAsync(() -> "huawei.jpg");
        CompletableFuture<Integer> priceFuture = CompletableFuture.supplyAsync(() -> 4000);
        CompletableFuture<String> infoFuture = CompletableFuture.supplyAsync(() -> "华为荣耀");

//        //组合多个任务(多个任务全部完成才返回)
//        CompletableFuture<Void> allOf = CompletableFuture.allOf(imgFuture, priceFuture, infoFuture);
//        //阻塞式等待所有任务都执行完成
//        allOf.get();
//        System.out.println("img:" + imgFuture.get() + ",price:" + priceFuture.get() + ",info:" + infoFuture.get());

        //组合多个任务(只要有一个任务完成就返回)
        CompletableFuture<Object> anyOf = CompletableFuture.anyOf(imgFuture, priceFuture, infoFuture);
        //阻塞等待一个任务完成
        Object res = anyOf.get();
        System.out.println(res);
    }
}
